#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <arpa/inet.h>
#include "socklib.h"
#include <errno.h>

#define HOSTLEN  256
#define BACKLOG  1

static int make_server_socket_q(int portnum,int backlog)
{
	struct sockaddr_in saddr;
	struct hostent *hp;
	char hostname[HOSTLEN];
	int sock_id;
	
	// 1.get a socket
	sock_id = socket(PF_INET,SOCK_STREAM,0);
	if (sock_id == -1){
		return -1;
	}
	
	// 2.build address and bind it to socket
	bzero((void *)&saddr,sizeof(saddr));
	gethostname(hostname,HOSTLEN); 		// where am i?
	hp = gethostbyname(hostname); 		// get info about host
	if (hp == NULL){
		return -1;
	}
										// fill in post part
	bcopy((void *)hp->h_addr,(void *)&saddr.sin_addr,hp->h_length);
	saddr.sin_port = htons(portnum); 	// fill in docket port
	saddr.sin_family = AF_INET; 		// fill in addr family
	if (bind(sock_id,(struct sockaddr *)&saddr,sizeof(saddr)) != 0){
		return -1;
	}
	// 3.arrange for incoming calls
	if (listen(sock_id,backlog) != 0){
		return -1;
	}

	
	return sock_id;
}

int make_server_socket(int portnum)
{
	return make_server_socket_q(portnum,BACKLOG);
}

int connect_to_server(const char *host,int portnum)
{
	int sock;
	struct sockaddr_in servaddr;
	struct hostent *hp;

	// 1.get a socket
	if ((sock = socket(AF_INET,SOCK_STREAM,0)) == -1){
		perror("get a socket");
		return -1;
	}

	// 2.connect to server
	bzero((void *)&servaddr,sizeof(servaddr));
	hp = gethostbyname(host);
	if (hp == NULL){
		perror(host);
		return -1;
	}
	bcopy(hp->h_addr,(struct sockaddr *)&servaddr,hp->h_length);
	servaddr.sin_addr.s_addr = inet_addr(host);
	servaddr.sin_port = htons(portnum);
	servaddr.sin_family = AF_INET;

	if (connect(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)) == -1){
		perror("connect to server");
		return -1;
	}

	return sock;
}

int sendMsg(int sockfd,const char *buf, int ms)
{
    int ret;
    struct timeval timeout;
    timeout.tv_sec = ms / 1000;
    timeout.tv_usec = (ms % 1000) * 1000;
    ret = setsockopt(sockfd, SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));
    if (ret < 0) {
        perror("setsockopt error");
        return ret;
    }
	ret = send(sockfd,buf,strlen(buf),0);
	if (ret < 0){
        if (errno == EAGAIN) {
            fprintf(stderr, "timeout error!\n");
            return errno;
        }
		perror("send error");
	}
	return ret;
}

int recvMsg(int sockfd,char *buf,int max_len, int ms)
{
    int ret;
    struct timeval timeout;
    timeout.tv_sec = ms / 1000;
    timeout.tv_usec = (ms % 1000) * 1000;
    ret = setsockopt(sockfd, SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
    if (ret < 0) {
        perror("setsockopt error");
        return ret;
    }
    memset(buf, 0, max_len);
	ret = recv(sockfd,buf,max_len,0);
	if (ret < 0){
        if (errno == EAGAIN) {
            fprintf(stderr, "timeout error!\n");
            return errno;
        }
		perror("recv error");
	}
	return ret;
}

